package com.syl.starter.mp.generate;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.FileType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import lombok.Setter;
import lombok.experimental.Accessors;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 原始超级代码生成
 * 支持超复杂的定制扩展
 *
 * @author syl
 * @create 2019-05-20 22:14
 **/
@Accessors(chain = true)
public class SuperCodeGenerate extends BaseCodeGenerate {

    @Setter
    private GlobalConfig globalConfig;
    @Setter
    private StrategyConfig strategyConfig;
    @Setter
    private TemplateConfig templateConfig;
    @Setter
    private InjectionConfig injectionConfig;
    @Setter
    private boolean moreDataSource = false;
    @Setter
    private IdType idType;

    public SuperCodeGenerate(String author){
        this(System.getProperty("user.dir"), author);
    }

    public SuperCodeGenerate(String projectPath, String author){
        this.projectPath = isEmpty(projectPath) ? null : projectPath + "\\";
        this.mapperRootPath = this.projectPath + "src\\main\\resources\\mapper\\";
        this.author = author;
    }

    /**
     * 获取默认生成策略 驼峰，bean中字段常量，去is，lombok，链式，rest，字段注解
     * @return
     */
    public StrategyConfig getDefaultStrategyConfig(){
        StrategyConfig strategyConfig = new StrategyConfig();
        strategyConfig.setNaming(NamingStrategy.underline_to_camel);// 表名和字段生成策略 驼峰
        strategyConfig.setEntityColumnConstant(true); // 字段常量
        strategyConfig.setEntityBooleanColumnRemoveIsPrefix(true); // is_xxx 去除 is_
        strategyConfig.setEntityLombokModel(true); // lombok
        strategyConfig.setEntityBuilderModel(true); // 链式调用
        strategyConfig.setRestControllerStyle(true); // 使用rest风格
        strategyConfig.setEntityTableFieldAnnotationEnable(true);// 使用字段注解
        return strategyConfig;
    }

    /**
     * 获取默认模板文件路径
     * 注意： 设置路径打头需要/
     * @return
     */
    public TemplateConfig getDefaultTemplateConfig(){
        TemplateConfig templateConfig = new TemplateConfig()
            .setEntity("/template/entity.java.vm")
            .setService("/template/service.java.vm")
            .setMapper("/template/mapper.java.vm")
            .setController("/template/controller.java.vm")
            .setServiceImpl(null)
            //.setController(null) // 默认生成控制器
        ;
        return templateConfig
        ;
    }

    /**
     * 获取生成过程中注入
     * @return
     */
    protected InjectionConfig getDefaultInjectionConfig(){
        InjectionConfig injectionConfig = new InjectionConfig() {
            public void initMap() {
                Map<String, Object> map = new HashMap();
                map.put("moreDataSource", moreDataSource);
                map.put("cacheClass", isEmpty(cacheClass) ?
                        "org.mybatis.caches.ehcache.LoggingEhcache" :
                        cacheClass);
                this.setMap(map);
            }
        };
        // 自定义 mapper 生成
        List<FileOutConfig> focList = new ArrayList<FileOutConfig>();
        focList.add(new FileOutConfig("/templates/mapper.xml.vm") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return mapperRootPath + tableInfo.getXmlName() + ".xml";
            }

        });
        injectionConfig.setFileCreate(new IFileCreate() {
            @Override
            public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {
                // 判断自定义文件夹是否需要创建,这里调用默认的方法
                checkDir(filePath);
                //对于已存在的文件，只需重复生成 entity
                File file = new File(filePath);
                boolean exist = file.exists();
                if(exist){
                    if (
                        filePath.endsWith(mapperSuffixName + ".xml") ||
                        FileType.ENTITY==fileType
                    ){
                        return true;
                    }else {
                        return false;
                    }
                }
                //不存在的文件都需要创建
                return  true;
            }
        });
        injectionConfig.setFileOutConfigList(focList);
        return injectionConfig;
    }

    /**
     * 获取默认的全局配置
     * @return
     */
    protected GlobalConfig getDefaultGlobalConfig(){
        GlobalConfig globalConfig = new GlobalConfig();
        globalConfig.setAuthor(this.author);
        globalConfig.setOutputDir(this.projectPath + JAVA_ROOT_PATH);
        globalConfig.setFileOverride(true);// 是否覆盖同名文件，默认是false
        globalConfig.setActiveRecord(false);// 不需要ActiveRecord特性的请改为false
        globalConfig.setEnableCache(false);// XML 二级缓存
        globalConfig.setBaseResultMap(true);// XML ResultMap
        globalConfig.setBaseColumnList(false);// XML columList
        globalConfig.setOpen(false); // 生成完成后不打开文件夹
        if(this.idType != null) globalConfig.setIdType(this.idType); // 配置主键id策略 空为自动
        globalConfig.setDateType(DateType.ONLY_DATE); // 仅使用 java.util.date
        /* 自定义文件命名，注意 %s 会自动填充表实体属性！ */
        globalConfig.setMapperName("%sDao");
        globalConfig.setXmlName("%s"+mapperSuffixName);
        globalConfig.setServiceName("%sService");
        globalConfig.setServiceImplName("%sServiceImpl");
        globalConfig.setControllerName("%sController");
        return globalConfig;
    }

    @Override
    public void start() throws Exception {
        if(dataSourceConfig == null)
            throw new Exception("数据源不能为空");
        if(packageConfig == null)
            throw new Exception("包配置不能为空");
        if(isEmpty(this.projectPath))
            throw new Exception("项目路径不能为空");
        if(tableNames == null || tableNames.length < 1)
            throw new Exception("表名称数组不能为空");
        AutoGenerator autoGenerator = new AutoGenerator();
        autoGenerator.setGlobalConfig(globalConfig == null ? getDefaultGlobalConfig() : globalConfig);
        StrategyConfig tempStrategyConfig =  strategyConfig == null ? getDefaultStrategyConfig() : strategyConfig;
        tempStrategyConfig.setTablePrefix(tablePrefixWipes).setInclude(tableNames);
        autoGenerator.setStrategy(tempStrategyConfig);
        TemplateConfig newTemplateConfig = templateConfig == null ? getDefaultTemplateConfig() : templateConfig;
        // 这个必须设置空 否则会在java目录下多出一个mapper
        newTemplateConfig.setXml(null);
        autoGenerator.setTemplate(newTemplateConfig);
        autoGenerator.setCfg(injectionConfig == null ? getDefaultInjectionConfig() : injectionConfig);
        autoGenerator.setDataSource(dataSourceConfig);
        autoGenerator.setPackageInfo(packageConfig);
        autoGenerator.execute();
    }

    /**
     * 设置项目路径
     * @param projectPath
     * @return
     */
    @Override
    public SuperCodeGenerate setProjectPath(String projectPath) {
        super.setProjectPath(projectPath);
        return this;
    }

    /**
     * 设置要生成的目标表数组
     * @param tableNames
     * @return
     */
    @Override
    public SuperCodeGenerate setTableNames(String... tableNames) {
        super.setTableNames(tableNames);
        return this;
    }

    /**
     * 设置去除表名称前缀
     * @param tablePrefixWipes
     * @return
     */
    @Override
    public SuperCodeGenerate setTablePrefixWipes(String... tablePrefixWipes) {
        super.setTablePrefixWipes(tablePrefixWipes);
        return this;
    }

    /**
     * 设置数据库连接
     * @param dataSourceConfig
     * @return
     */
    @Override
    public SuperCodeGenerate setDataSourceConfig(DataSourceConfig dataSourceConfig) {
        super.setDataSourceConfig(dataSourceConfig);
        return this;
    }

    /**
     * 设置包配置
     * @param packageConfig
     * @return
     */
    @Override
    public SuperCodeGenerate setPackageConfig(PackageConfig packageConfig) {
        super.setPackageConfig(packageConfig);
        return this;
    }

}
